package com.cruel_wandering.wifi_geo_predictor.wifi_simulation;

import java.util.LinkedList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.location.Location;

public class WifiSimDB
{
	public static final String DATABASE_NAME = "vava";
	private static final int DATABASE_VERSION = 1;

	public static final String COL_AP_MAC = "mac_addr";
	public static final String COL_AP_LNG = "longtitude";
	public static final String COL_AP_LAT = "latitude";
	public static final String COL_AP_RADIUS = "radius";
	public static final String COL_AP_ALT = "altitude";

	private SQLiteDatabase db;
	private Context ctx;
	private String tableName;

	public WifiSimDB(Context ctx, String tableName)
  {
		this.tableName = tableName;
		this.ctx = ctx;
//		db = new WifiSimDbOpenHelper(ctx).getWritableDatabase();
  }

	public long insert(MyAccessPoint entry)
	{
		ContentValues dbEntry = new ContentValues();

		dbEntry.put(COL_AP_MAC, entry.getMacAddr());
		dbEntry.put(COL_AP_LNG, entry.getLongtitude());
		dbEntry.put(COL_AP_LAT, entry.getLatitude());
		dbEntry.put(COL_AP_RADIUS, entry.getRadius());
		dbEntry.put(COL_AP_ALT, entry.getAltitude());
		return db.insert(this.tableName, null, dbEntry);
	}


	public List<MyAccessPoint> getAll()
	{
		return getByQueryPredicate(new QueryPredicate()
			{
				public boolean apply(MyAccessPoint ap)
				{
					return true;
				}
			});
	}

	public List<MyAccessPoint> getAPinRange(final Location loc, double radius)
	{
		final double rangeRadius = radius;

		return getByQueryPredicate(new QueryPredicate()
			{
				public boolean apply(MyAccessPoint ap)
				{
					float[] res = new float[1];

					Location.distanceBetween(loc.getLatitude(),
						loc.getLongitude(), ap.getLatitude(), ap.getLongtitude(), res);
					return res[0] < rangeRadius;
				}
			});
	}

	public List<MyAccessPoint> getAvailableAPs(Location location)
	{
		final Location loc = location;

		return getByQueryPredicate(new QueryPredicate()
			{
				public boolean apply(MyAccessPoint ap)
				{
					float[] res = new float[1];

					Location.distanceBetween(loc.getLatitude(),
						loc.getLongitude(), ap.getLatitude(), ap.getLongtitude(), res);
					return res[0] < ap.getRadius();
				}
			});
	}

	private List<MyAccessPoint> getByQueryPredicate(QueryPredicate p)
	{
		List<MyAccessPoint> list = new LinkedList<MyAccessPoint>();
		Cursor c;

		db = new WifiSimDbOpenHelper(ctx).getReadableDatabase();
		c = db.rawQuery("SELECT * FROM " + this.tableName, null);
		if (c.moveToFirst())
		{
			do {
				int mac_ind = c.getColumnIndex(COL_AP_MAC);
				int lng_ind = c.getColumnIndex(COL_AP_LNG);
				int lat_ind = c.getColumnIndex(COL_AP_LAT);
				int rad_ind = c.getColumnIndex(COL_AP_RADIUS);
				MyAccessPoint ap = new MyAccessPoint(c.getString(mac_ind), c.getDouble(lng_ind),
					c.getDouble(lat_ind), c.getDouble(rad_ind)); 
	
				if (p.apply(ap))
				{
					list.add(ap);
				}
			} while (c.moveToNext());
		}

		if (!c.isClosed())
			c.close();
		if (db.isOpen())
			db.close();
		return list;
	}

	private interface QueryPredicate
	{
		public boolean apply(MyAccessPoint c);
	}

	private class WifiSimDbOpenHelper extends SQLiteOpenHelper
	{
		public WifiSimDbOpenHelper(Context ctx)
	  {
			super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
	  }

		@Override
		public void onCreate(SQLiteDatabase db)
		{
			db.execSQL("CREATE TABLE " + tableName + " " +
				"(_id integer primary key autoincrement, " +
				COL_AP_MAC + " TEXT, " +
				COL_AP_LNG + " REAL, " + COL_AP_LAT + " REAL," +
			  COL_AP_ALT + " REAL, " + COL_AP_RADIUS + "REAL);");
		}

		@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
			/* Nothing to do */
    }
  }
}